#include "finger_api.h"

#if (_SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_) && (_SAFETY_VERIFYFUNCTION_ENABLE_)

/**
 * @brief 根据格式生成报文
 *
 * @param MasterCmd - 主命令
 * @param SubCmd    - 子命令
 * @param pDataIn   - 应用层层附带数据
 * @param SizeIn    - 应用附带数据长度
 * @param pDataOut  - 协议层数据
 * @param pSizeOut  - 协议层数据长度
 * @return bool     - 生成结果（true-成功，false-失败）
 */
static bool FingerGenerateMessageAccordingToTheFormat(uint8_t MasterCmd, uint8_t SubCmd, const void *pDataIn, uint16_t SizeIn, void *pDataOut, uint16_t *pSizeOut);

static bool FingerGenerateMessageAccordingToTheFormat(uint8_t MasterCmd, uint8_t SubCmd, const void *pDataIn, uint16_t SizeIn, void *pDataOut, uint16_t *pSizeOut)
{
  if ((SizeIn <= FINGER_APPLICATION_MAX_DATA_BIT_LENGTH) && (pDataOut != NULL) && (pSizeOut != NULL))
  {
    FingerTxProtocolFormat_t *pProtocolFormat = (FingerTxProtocolFormat_t *)pDataOut;
    uint8_t Password[FINGER_PROTOCOL_PASSWORD_BIT_LENGTH] = {0x00, 0x00, 0x00, 0x00};
    uint8_t FrameHeader[FINGER_FRAME_HEADE_BIT_LENGTH] = {0xF1, 0x1F, 0xE2, 0x2E, 0xB6, 0x6B, 0xA8, 0x8A};

    pProtocolFormat->SubCommand = SubCmd;
    pProtocolFormat->MasterCommand = MasterCmd;
    memcpy(pProtocolFormat->Data, pDataIn, SizeIn);
    memcpy(pProtocolFormat->Password, Password, FINGER_PROTOCOL_PASSWORD_BIT_LENGTH);
    uint8_t CrcValue = FingerCalculateCrcValue(pProtocolFormat->Password, (FINGER_TX_APPLICATION_DATA_LENGTH(SizeIn) - 1));
    pProtocolFormat->Data[SizeIn] = CrcValue;

    uint16_t MessageSize = FINGER_TX_APPLICATION_DATA_LENGTH(SizeIn);
    pProtocolFormat->DataSize[1] = (uint8_t)(MessageSize & 0x00FF);
    pProtocolFormat->DataSize[0] = (uint8_t)((MessageSize & 0xFF00) >> 8);
    memcpy(pProtocolFormat->FrameHead, FrameHeader, FINGER_FRAME_HEADE_BIT_LENGTH);
    pProtocolFormat->FramHeadeCrc = FingerCalculateCrcValue(pProtocolFormat->FrameHead, FINGER_FRAME_HEADE_BIT_LENGTH + FINGER_APPLICATION_DATA_SIZE_BIT_LENGTH);

    *pSizeOut = FINGER_TX_PROTOCOL_TOTAL_LENGTH(SizeIn);
    return true;
  }

  return false;
}

uint8_t FingerCalculateCrcValue(const uint8_t *pDataIn, uint16_t DataSize)
{
  uint32_t CrcValue = 0;

  for (uint16_t i = 0; i < DataSize; i++)
  {
    CrcValue += pDataIn[i];
  }

  return (uint8_t)((~CrcValue) + 1);
}

bool FinigerBuildTheUserRegistrationMessage(uint8_t RegisterCount, void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_REGISTRATION, &RegisterCount, 1, pDataOut, pSizeOut);
}

bool FingerQueryRegistrationResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_REGISTRATION_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerSaveFingerprintTemplateMessage(uint16_t TemplateId, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[2] = {0};

  TemporaryData[0] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((TemplateId & 0x00FF));
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_SAVE_TEMPLATE, TemporaryData, 2, pDataOut, pSizeOut);
}

bool FingerBuildGetSaveFingerprintTemplateResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_SAVE_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildCancelTheCurrentActionMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_CANCEL_REGISTRATION, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildUpdateStorageFeatureValueMessage(uint16_t TemplateId, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[2] = {0};

  TemporaryData[0] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((TemplateId & 0x00FF));
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_UPDATE_STORAGE_FEATURE_VALUE, TemporaryData, 2, pDataOut, pSizeOut);
}

bool FingerBuildCheckFeatureUpdateResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_VIEW_STORAGE_FEATURE_VALUE_UPDATE_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildAutomaticRegistrationMessage(bool WaitFinger, uint8_t PressTimes, uint16_t TemplateId, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[4] = {0};

  TemporaryData[0] = WaitFinger;
  TemporaryData[1] = PressTimes;
  TemporaryData[2] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[3] = (uint8_t)((TemplateId & 0x00FF));
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_AUTO_REGISTRATION, TemporaryData, 4, pDataOut, pSizeOut);
}

bool FingerBuildMatchingMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_MATCHING, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildQueryMatchingResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_MATCHING_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildMatchingSynchronousMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_MATCHING_SYNCHRONOUS, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildFeatureClearanceMessage(FingerDeleteMode_t Mode, uint16_t *pTemplateIdIn, uint8_t NumberOfDelete, void *pDataOut, uint16_t *pSizeOut)
{
  uint16_t MessageDataSize = 0;
  uint8_t TemporaryData[FINGER_APPLICATION_MAX_DATA_BIT_LENGTH] = {0};

  switch (Mode)
  {
  case FINGER_DELETE_ONLY:
  {
    if (pTemplateIdIn == NULL)
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_ONLY;
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0x00FF));
  }
  break;

  case FINGER_DELETE_ALL_USER:
  {
    TemporaryData[MessageDataSize++] = FINGER_DELETE_ALL_USER;
    TemporaryData[MessageDataSize++] = 0;
    TemporaryData[MessageDataSize++] = 0;
  }
  break;

  case FINGER_DELETE_CODE_MASK:
  {
    if ((pTemplateIdIn == NULL) || ((NumberOfDelete == 0) || (NumberOfDelete > FINGER_NUMBER_OF_REGISTERED_USERS)))
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_CODE_MASK;
    for (uint8_t i = 0; i < NumberOfDelete; i++)
    {
      TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[i] & 0xFF00) >> 8);
      TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[i] & 0x00FF));
    }
  }
  break;

  case FINGER_DELETE_BLOCK:
  {
    if (pTemplateIdIn == NULL)
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_BLOCK;
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0x00FF));
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[1] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[1] & 0x00FF));
  }
  break;

  default:
    return false;
  }

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_CLEARANCE, TemporaryData, MessageDataSize, pDataOut, pSizeOut);
}

bool FingerBuildQueryFeatureClearanceResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_FEATURE_CLEARANCE_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildQueryEncodingExistenceMessage(uint16_t TemplateId, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[2] = {0};

  TemporaryData[0] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((TemplateId & 0x00FF));
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_ENCODING_EXISTENCE, TemporaryData, 2, pDataOut, pSizeOut);
}

bool FingerBuildQueryStorageDistributionMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_STORAGE_DISTRIBUTION, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildQueryFingerOnlineStatusMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_FINGER_ONLINE_STATUS, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildFeatureClearanceSynchronousMessage(FingerDeleteMode_t Mode, uint16_t *pTemplateIdIn, uint8_t NumberOfDelete, void *pDataOut, uint16_t *pSizeOut)
{
  uint16_t MessageDataSize = 0;
  uint8_t TemporaryData[FINGER_APPLICATION_MAX_DATA_BIT_LENGTH] = {0};

  switch (Mode)
  {
  case FINGER_DELETE_ONLY:
  {
    if (pTemplateIdIn == NULL)
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_ONLY;
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0x00FF));
  }
  break;

  case FINGER_DELETE_ALL_USER:
  {
    TemporaryData[MessageDataSize++] = FINGER_DELETE_ALL_USER;
    TemporaryData[MessageDataSize++] = 0;
    TemporaryData[MessageDataSize++] = 0;
  }
  break;

  case FINGER_DELETE_CODE_MASK:
  {
    if ((pTemplateIdIn == NULL) || ((NumberOfDelete == 0) || (NumberOfDelete > FINGER_NUMBER_OF_REGISTERED_USERS)))
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_CODE_MASK;
    for (uint8_t i = 0; i < NumberOfDelete; i++)
    {
      TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[i] & 0xFF00) >> 8);
      TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[i] & 0x00FF));
    }
  }
  break;

  case FINGER_DELETE_BLOCK:
  {
    if (pTemplateIdIn == NULL)
      return false;

    TemporaryData[MessageDataSize++] = FINGER_DELETE_BLOCK;
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[0] & 0x00FF));
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[1] & 0xFF00) >> 8);
    TemporaryData[MessageDataSize++] = (uint8_t)((pTemplateIdIn[1] & 0x00FF));
  }
  break;

  default:
    return false;
  }

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_CLEARANCE_SYNCHRONOUS, TemporaryData, MessageDataSize, pDataOut, pSizeOut);
}

bool FingerBuildRegisterConfirmationMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_REGISTER_CONFIRMATION, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildQueryRegisterConfirmationResultMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_QUERY_REGISTER_CONFIRMATION_RESULT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildFeatureInformationDownloadMessage(uint16_t TemplateId, uint16_t FeatureSize, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[4] = {0};

  if ((FeatureSize == 0) || (FeatureSize > FINGER_FEATURE_MAX_SIZE))
    return false;

  TemporaryData[0] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((TemplateId & 0x00FF));
  TemporaryData[2] = (uint8_t)((FeatureSize & 0xFF00) >> 8);
  TemporaryData[3] = (uint8_t)((FeatureSize & 0x00FF));

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_INFORMATION_DOWNLOAD, TemporaryData, 4, pDataOut, pSizeOut);
}

bool FingerBuildFeatureDataDownloadMessage(uint16_t DataOffset, const uint8_t *pFeatureIn, uint8_t DataSize, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t MessageDataSize = 0;
  uint8_t TemporaryData[FINGER_APPLICATION_MAX_DATA_BIT_LENGTH] = {0};

  if ((DataSize == 0) || (DataSize > (FINGER_APPLICATION_MAX_DATA_BIT_LENGTH - 9)))
    return false;

  if (pFeatureIn == NULL)
    return false;

  TemporaryData[MessageDataSize++] = (uint8_t)((DataOffset & 0xFF00) >> 8);
  TemporaryData[MessageDataSize++] = (uint8_t)((DataOffset & 0x00FF));
  memcpy(&TemporaryData[MessageDataSize], pFeatureIn, DataSize);
  MessageDataSize += DataSize;

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_DATA_DOWNLOAD, TemporaryData, MessageDataSize, pDataOut, pSizeOut);
}

bool FingerBuildFeatureInformationUploadMessage(uint16_t TemplateId, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[2] = {0};

  TemporaryData[0] = (uint8_t)((TemplateId & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((TemplateId & 0x00FF));

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_INFORMATION_UPLOAD, TemporaryData, 2, pDataOut, pSizeOut);
}

bool FingerBuildFeatureDataUploadMessage(uint16_t DataOffset, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[2] = {0};

  TemporaryData[0] = (uint8_t)((DataOffset & 0xFF00) >> 8);
  TemporaryData[1] = (uint8_t)((DataOffset & 0x00FF));

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_FINGERPRINT, FINGER_FEATURE_DATA_UPLOAD, TemporaryData, 2, pDataOut, pSizeOut);
}

bool FingerBuildPasswordSettingMessage(uint8_t *pPasswordIn, void *pDataOut, uint16_t *pSizeOut)
{
  if (pPasswordIn == NULL)
    return false;

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_PASSWORD_SETTING, pPasswordIn, FINGER_PROTOCOL_PASSWORD_BIT_LENGTH, pDataOut, pSizeOut);
}

bool FingerBuildResetModuleMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_RESET_MODULE, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildGetTemplateQuantityMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_GET_TEMPLATE_QUANTITY, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildGetGainMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_GET_GAIN, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildGetMatchingThresholdMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_GET_MATCHING_THRESHOLD, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildSleepModeMessage(FingerSleepMode_t Mode, void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_SLEEP_MODE, &Mode, 1, pDataOut, pSizeOut);
}

bool FingerBuildSetMaximumRegistrationTimesMessage(uint8_t Times, void *pDataOut, uint16_t *pSizeOut)
{
  if ((Times < FINGER_MINIMUM_NUMBER_OF_CONCATENATIONS) || (Times > FINGER_MAXIMUM_NUMBER_OF_CONCATENATIONS))
    return false;

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_SET_MAXIMUM_REGISTRATION_TIMES, &Times, 1, pDataOut, pSizeOut);
}

bool FingerBuildSetLedControlInformationMessage(FingerLedContorlType_t LedCtrlType, FingerLedHintMode_t LedHintMode, uint8_t Parameter1, uint8_t Parameter2, uint8_t Parameter3, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[5] = {0};

  if ((Parameter1 > 100) || (Parameter2 > 100) || (Parameter3 > 100))
    return false;

  TemporaryData[0] = LedCtrlType;
  TemporaryData[1] = LedHintMode;
  TemporaryData[2] = Parameter1;
  TemporaryData[3] = Parameter2;
  TemporaryData[4] = Parameter3;

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_SET_LED_CONTROL_INFORMATION, TemporaryData, 5, pDataOut, pSizeOut);
}

bool FingerBuildGetSystemStrategyMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_GET_SYSTEM_STRATEGY, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildSetSystemStrategyMessage(uint32_t Policy, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[4] = {0};

  TemporaryData[0] = (uint8_t)((Policy & 0xFF000000) >> 24);
  TemporaryData[1] = (uint8_t)((Policy & 0x00FF0000) >> 16);
  TemporaryData[2] = (uint8_t)((Policy & 0x0000FF00) >> 8);
  TemporaryData[3] = (uint8_t)((Policy & 0x000000FF));

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_SYSTEM, FINGER_SET_SYSTEM_STRATEGY, TemporaryData, 4, pDataOut, pSizeOut);
}

bool FingerBuildReadDeviceEncodingMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_MAINTENANCE, FINGER_READ_DEVICE_ENCODING, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildHeartbeatMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_MAINTENANCE, FINGER_HEARTBEAT, NULL, 0, pDataOut, pSizeOut);
}

bool FingerBuildSetBaudRateMessage(uint32_t BaudRate, void *pDataOut, uint16_t *pSizeOut)
{
  uint8_t TemporaryData[4] = {0};

  TemporaryData[0] = (uint8_t)((BaudRate & 0xFF000000) >> 24);
  TemporaryData[1] = (uint8_t)((BaudRate & 0x00FF0000) >> 16);
  TemporaryData[2] = (uint8_t)((BaudRate & 0x0000FF00) >> 8);
  TemporaryData[3] = (uint8_t)((BaudRate & 0x000000FF));

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_MAINTENANCE, FINGER_SET_BAUD_RATE, TemporaryData, 4, pDataOut, pSizeOut);
}

bool FingerBuildSetCommunicationPasswordMessage(uint8_t *pPasswordIn, void *pDataOut, uint16_t *pSizeOut)
{
  if (pPasswordIn == NULL)
    return false;

  return FingerGenerateMessageAccordingToTheFormat(COMMAND_MAINTENANCE, FINGER_SET_COMMUNICATION_PASSWORD, pPasswordIn, FINGER_PROTOCOL_PASSWORD_BIT_LENGTH, pDataOut, pSizeOut);
}

bool FingerBuildGetFirmwareVersionMessage(void *pDataOut, uint16_t *pSizeOut)
{
  return FingerGenerateMessageAccordingToTheFormat(COMMAND_MAINTENANCE, FINGER_GET_FIRMWARE_VERSION, NULL, 0, pDataOut, pSizeOut);
}

bool FingerParseRegistrationMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQueryRegistrationResultMessage(const uint8_t *pMessageIn, uint16_t *pTemplateIdOut, uint8_t *pProgressOut)
{
  if (pMessageIn != NULL)
  {
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pProgressOut != NULL)
    {
      *pProgressOut = pMessageIn[0];
    }

    pMessageIn++;
    return true;
  }

  return false;
}

bool FingerParseSaveFingerprintTemplateMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQuerySaveFingerprintTemplateResultMessage(const uint8_t *pMessageIn, uint16_t *pTemplateIdOut)
{
  if (pMessageIn != NULL)
  {
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pTemplateIdOut += 2;
    return true;
  }

  return false;
}

bool FingerParseCancelRegistrationOrMatchingMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseUpdateStorageFeatureValueMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseCheckFeatureUpdateResultMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseAutomaticRegistrationMessage(const uint8_t *pMessageIn, uint8_t *pRegisterCountOut, uint16_t *pTemplateIdOut, uint8_t *pProgressOut)
{
  if (pMessageIn != NULL)
  {
    if (pRegisterCountOut != NULL)
    {
      *pRegisterCountOut = pMessageIn[0];
    }

    pMessageIn++;
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pProgressOut != NULL)
    {
      *pProgressOut = pMessageIn[0];
    }

    pMessageIn++;
    return true;
  }

  return false;
}

bool FingerParseMatchingMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQueryMatchingResultMessage(const uint8_t *pMessageIn, uint16_t *pMatchResultOut, uint16_t *pMatchScoreOut, uint16_t *pTemplateIdOut)
{
  if (pMessageIn != NULL)
  {
    if (pMatchResultOut != NULL)
    {
      *pMatchResultOut = pMessageIn[0] << 8;
      *pMatchResultOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pMatchScoreOut != NULL)
    {
      *pMatchScoreOut = pMessageIn[0] << 8;
      *pMatchScoreOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseFeatureClearanceMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQueryFeatureClearanceResultMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQueryFingerIdExistenceMessage(const uint8_t *pMessageIn, uint8_t *pStatusOut, uint16_t *pTemplateIdOut)
{
  if (pMessageIn != NULL)
  {
    if (pStatusOut != NULL)
    {
      *pStatusOut = pMessageIn[0];
    }

    pMessageIn++;
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseQueryStorageDistributionMessage(const uint8_t *pMessageIn, uint16_t *pNumberOfRegisterOut, uint8_t TemplateIdOut[8])
{
  if (pMessageIn != NULL)
  {
    if (pNumberOfRegisterOut != NULL)
    {
      *pNumberOfRegisterOut = pMessageIn[0] << 8;
      *pNumberOfRegisterOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (TemplateIdOut != NULL)
    {
      for (uint8_t i = 0; i < 8; i++)
      {
        TemplateIdOut[i] = pMessageIn[i];
      }
    }

    pMessageIn += 8;
    return true;
  }

  return false;
}

bool FingerParseQueryFingerOnlineStatusMessage(const uint8_t *pMessageIn, uint8_t *pStatusOut)
{
  if (pMessageIn != NULL)
  {
    if (pStatusOut != NULL)
    {
      *pStatusOut = pMessageIn[0];
    }

    pMessageIn++;
    return true;
  }

  return false;
}

bool FingerParseFeatureClearanceSynchronousMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseRegisterConfirmationMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseQueryRegisterConfirmationResultMessage(const uint8_t *pMessageIn, uint16_t *pMatchResultOut, uint16_t *pMatchScoreOut, uint16_t *pTemplateIdOut)
{
  if (pMessageIn != NULL)
  {
    if (pMatchResultOut != NULL)
    {
      *pMatchResultOut = pMessageIn[0] << 8;
      *pMatchResultOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pMatchScoreOut != NULL)
    {
      *pMatchScoreOut = pMessageIn[0] << 8;
      *pMatchScoreOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pTemplateIdOut != NULL)
    {
      *pTemplateIdOut = pMessageIn[0] << 8;
      *pTemplateIdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseFeatureInformationDownloadMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseFeatureDataDownloadMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseFeatureInformationUploadMessage(const uint8_t *pMessageIn, uint16_t *pFeatureSizeOut)
{
  if (pMessageIn != NULL)
  {
    if (pFeatureSizeOut != NULL)
    {
      *pFeatureSizeOut = pMessageIn[0] << 8;
      *pFeatureSizeOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseFeatureDataUploadMessage(const uint8_t *pMessageIn, uint16_t *pDataOffsetOut, uint8_t *pDataOut)
{
  if (pMessageIn != NULL)
  {
    if (pDataOffsetOut != NULL)
    {
      *pDataOffsetOut = pMessageIn[0] << 8;
      *pDataOffsetOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    if (pDataOut != NULL)
    {
      for (uint16_t i = 0; i < FINGER_APPLICATION_MAX_DATA_BIT_LENGTH; i++)
      {
        pDataOut[i] = pMessageIn[i];
      }
    }

    pMessageIn += FINGER_APPLICATION_MAX_DATA_BIT_LENGTH;
    return true;
  }

  return false;
}

bool FingerParsePasswordSettingMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseResetModuleMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseGetTemplateQuantityMessage(const uint8_t *pMessageIn, uint8_t *pTemplateQuantityOut)
{
  if (pMessageIn != NULL)
  {
    if (pTemplateQuantityOut != NULL)
    {
      uint16 TemplateQuantity = 0;

      TemplateQuantity = pMessageIn[0] << 8;
      TemplateQuantity |= pMessageIn[1];

      *pTemplateQuantityOut = (uint8_t)TemplateQuantity;
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseGetGainMessage(const uint8_t *pMessageIn, uint8_t *pShiftOut, uint8_t *pGainOut, uint8_t *pPxlCtrlOut)
{
  if (pMessageIn != NULL)
  {
    if (pShiftOut != NULL)
    {
      *pShiftOut = pMessageIn[0];
    }

    pMessageIn++;
    if (pGainOut != NULL)
    {
      *pGainOut = pMessageIn[0];
    }

    pMessageIn++;
    if (pPxlCtrlOut != NULL)
    {
      *pPxlCtrlOut = pMessageIn[0];
    }

    pMessageIn++;
    return true;
  }

  return false;
}

bool FingerParseGetMatchingThresholdMessage(const uint8_t *pMessageIn, uint16_t *pThresholdOut)
{
  if (pMessageIn != NULL)
  {
    if (pThresholdOut != NULL)
    {
      *pThresholdOut = pMessageIn[0] << 8;
      *pThresholdOut |= pMessageIn[1];
    }

    pMessageIn += 2;
    return true;
  }

  return false;
}

bool FingerParseSetSleepModeMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseSetMaximumRegistrationTimesMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseSetLedControlInformationMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseGetSystemStrategyMessage(const uint8_t *pMessageIn, uint32_t *pPolicyOut)
{
  if (pMessageIn != NULL)
  {
    if (pPolicyOut != NULL)
    {
      *pPolicyOut = pMessageIn[0] << 24;
      *pPolicyOut |= pMessageIn[1] << 16;
      *pPolicyOut |= pMessageIn[2] << 8;
      *pPolicyOut |= pMessageIn[3];
    }

    pMessageIn += 4;
    return true;
  }

  return false;
}

bool FingerParseSetSystemStrategyMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseGetModuleIdMessage(const uint8_t *pMessageIn, void *pModuleIdOut)
{
  if (pMessageIn != NULL)
  {
    if (pModuleIdOut != NULL)
    {
      memcpy(pModuleIdOut, pMessageIn, FINGER_MODULE_SN_LENGTH);
    }

    pMessageIn += FINGER_MODULE_SN_LENGTH;
    return true;
  }

  return false;
}

bool FingerParseHeartbeatMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseSetBaudRateMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseSetCommunicationPasswordMessage(const uint8_t *pMessageIn)
{
  return true;
}

bool FingerParseGetFirmwareVersionNumberMessage(const uint8_t *pMessageIn, void *pFirmwareVersionNumberOut)
{
  if (pMessageIn != NULL)
  {
    if (pFirmwareVersionNumberOut != NULL)
    {
      memcpy(pFirmwareVersionNumberOut, pMessageIn, FINGER_LENGTH_OF_VERSION_INFORMATION);
    }

    pMessageIn += FINGER_LENGTH_OF_VERSION_INFORMATION;
    return true;
  }

  return false;
}

#endif
